"""
现代化Plotly K线图模块
"""
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from typing import Optional
import tempfile
import os
import webbrowser
from datetime import datetime

class PlotlyKlineChart:
    """现代化Plotly K线图"""
    
    def __init__(self):
        self.fig = None
        self.temp_file = None
        
    def create_kline_chart(self, data: pd.DataFrame, symbol: str, period: str = "1d") -> str:
        """创建K线图并返回HTML文件路径"""
        try:
            # 计算技术指标
            data = self.calculate_indicators(data)
            
            # 创建子图
            self.fig = make_subplots(
                rows=4, cols=1,
                shared_xaxes=True,
                vertical_spacing=0.03,
                subplot_titles=('K线图', '成交量', 'MACD', 'RSI'),
                row_width=[0.2, 0.1, 0.1, 0.1]
            )
            
            # 添加K线图
            self.add_candlestick(data, symbol, period)
            
            # 添加移动平均线
            self.add_moving_averages(data)
            
            # 添加成交量
            self.add_volume(data)
            
            # 添加MACD
            self.add_macd(data)
            
            # 添加RSI
            self.add_rsi(data)
            
            # 设置布局
            self.set_layout(symbol, period)
            
            # 保存为HTML文件
            return self.save_to_html()
            
        except Exception as e:
            print(f"创建K线图失败: {e}")
            return None
            
    def calculate_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
        """计算技术指标"""
        data = data.copy()
        
        # 移动平均线
        data['MA5'] = data['close'].rolling(window=5).mean()
        data['MA10'] = data['close'].rolling(window=10).mean()
        data['MA20'] = data['close'].rolling(window=20).mean()
        
        # MACD
        exp1 = data['close'].ewm(span=12).mean()
        exp2 = data['close'].ewm(span=26).mean()
        data['MACD'] = exp1 - exp2
        data['MACD_signal'] = data['MACD'].ewm(span=9).mean()
        data['MACD_histogram'] = data['MACD'] - data['MACD_signal']
        
        # RSI
        delta = data['close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
        rs = gain / loss
        data['RSI'] = 100 - (100 / (1 + rs))
        
        return data
        
    def add_candlestick(self, data: pd.DataFrame, symbol: str, period: str):
        """添加K线图"""
        self.fig.add_trace(
            go.Candlestick(
                x=data.index,
                open=data['open'],
                high=data['high'],
                low=data['low'],
                close=data['close'],
                name='K线',
                increasing_line_color='#ff4444',  # 红涨
                decreasing_line_color='#44ff44',  # 绿跌
                increasing_fillcolor='#ff4444',
                decreasing_fillcolor='#44ff44'
            ),
            row=1, col=1
        )
        
    def add_moving_averages(self, data: pd.DataFrame):
        """添加移动平均线"""
        # MA5
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['MA5'],
                mode='lines',
                name='MA5',
                line=dict(color='#ffff00', width=1),
                opacity=0.8
            ),
            row=1, col=1
        )
        
        # MA10
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['MA10'],
                mode='lines',
                name='MA10',
                line=dict(color='#ff00ff', width=1),
                opacity=0.8
            ),
            row=1, col=1
        )
        
        # MA20
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['MA20'],
                mode='lines',
                name='MA20',
                line=dict(color='#00ffff', width=1),
                opacity=0.8
            ),
            row=1, col=1
        )
        
    def add_volume(self, data: pd.DataFrame):
        """添加成交量"""
        colors = ['#ff4444' if close >= open_price else '#44ff44' 
                 for close, open_price in zip(data['close'], data['open'])]
        
        self.fig.add_trace(
            go.Bar(
                x=data.index,
                y=data['volume'],
                name='成交量',
                marker_color=colors,
                opacity=0.6
            ),
            row=2, col=1
        )
        
    def add_macd(self, data: pd.DataFrame):
        """添加MACD指标"""
        # MACD线
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['MACD'],
                mode='lines',
                name='MACD',
                line=dict(color='#ffff00', width=1)
            ),
            row=3, col=1
        )
        
        # 信号线
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['MACD_signal'],
                mode='lines',
                name='Signal',
                line=dict(color='#ff00ff', width=1)
            ),
            row=3, col=1
        )
        
        # 柱状图
        colors = ['#ff4444' if h >= 0 else '#44ff44' for h in data['MACD_histogram']]
        self.fig.add_trace(
            go.Bar(
                x=data.index,
                y=data['MACD_histogram'],
                name='MACD柱',
                marker_color=colors,
                opacity=0.6
            ),
            row=3, col=1
        )
        
    def add_rsi(self, data: pd.DataFrame):
        """添加RSI指标"""
        self.fig.add_trace(
            go.Scatter(
                x=data.index,
                y=data['RSI'],
                mode='lines',
                name='RSI',
                line=dict(color='#ffff00', width=1)
            ),
            row=4, col=1
        )
        
        # 超买超卖线
        self.fig.add_hline(y=70, line_dash="dash", line_color="#ff4444", 
                          annotation_text="超买", row=4, col=1)
        self.fig.add_hline(y=30, line_dash="dash", line_color="#44ff44", 
                          annotation_text="超卖", row=4, col=1)
        self.fig.add_hline(y=50, line_dash="solid", line_color="gray", 
                          opacity=0.5, row=4, col=1)
        
    def set_layout(self, symbol: str, period: str):
        """设置图表布局"""
        period_name = {"1d": "日线", "1wk": "周线", "1mo": "月线"}.get(period, "日线")
        
        self.fig.update_layout(
            title=f"{symbol} - {period_name}",
            title_font_size=16,
            title_font_color="white",
            template="plotly_dark",  # 深色主题
            showlegend=True,
            legend=dict(
                orientation="h",
                yanchor="bottom",
                y=1.02,
                xanchor="right",
                x=1
            ),
            margin=dict(l=50, r=50, t=80, b=50),
            height=800,
            hovermode='x unified'
        )
        
        # 设置x轴
        self.fig.update_xaxes(
            rangeslider_visible=False,
            showgrid=True,
            gridcolor='rgba(128,128,128,0.3)'
        )
        
        # 设置y轴
        self.fig.update_yaxes(
            showgrid=True,
            gridcolor='rgba(128,128,128,0.3)'
        )
        
        # RSI y轴范围
        self.fig.update_yaxes(range=[0, 100], row=4, col=1)
        
    def save_to_html(self) -> str:
        """保存为HTML文件"""
        try:
            # 创建临时文件
            temp_dir = tempfile.gettempdir()
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            self.temp_file = os.path.join(temp_dir, f"kline_chart_{timestamp}.html")

            # 保存HTML
            self.fig.write_html(
                self.temp_file,
                config={
                    'displayModeBar': True,
                    'displaylogo': False,
                    'modeBarButtonsToRemove': ['pan2d', 'lasso2d', 'select2d'],
                    'toImageButtonOptions': {
                        'format': 'png',
                        'filename': 'kline_chart',
                        'height': 800,
                        'width': 1200,
                        'scale': 2
                    }
                }
            )

            return self.temp_file

        except Exception as e:
            print(f"保存HTML文件失败: {e}")
            return None

    def save_to_image(self, width: int = 1200, height: int = 800) -> str:
        """保存为PNG图片文件，用于在tkinter中显示"""
        try:
            # 创建临时文件
            temp_dir = tempfile.gettempdir()
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            image_file = os.path.join(temp_dir, f"kline_chart_{timestamp}.png")

            # 保存PNG图片
            self.fig.write_image(
                image_file,
                format="png",
                width=width,
                height=height,
                scale=2  # 高分辨率
            )

            return image_file

        except Exception as e:
            print(f"保存PNG图片失败: {e}")
            return None
            
    def open_in_browser(self, html_file: str):
        """在浏览器中打开图表"""
        if html_file and os.path.exists(html_file):
            webbrowser.open(f'file://{html_file}')
            
    def cleanup(self):
        """清理临时文件"""
        if self.temp_file and os.path.exists(self.temp_file):
            try:
                os.remove(self.temp_file)
            except:
                pass
